﻿using BibleBase;
using EXCEL_LIB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Util;
using WORD_LIB;
using Excel = Microsoft.Office.Interop.Excel;

namespace NVI_LIB
{
    public class IndiceDeTemasParser
    {
        public static char GuionLargoChar { get { return '–'; } }
        public static string GuionLargoStr { get { return GuionLargoChar.ToString(); } }

        WordSession session;
        Bible NVI { get; set; }
        Bible RV { get; set; }

        public IndiceDeTemasParser(string indiceDeTemasPath,
                                   string mapeoVocabularioTemasBinPath,
                                   string modifEntradasBinPath,
                                   Bible nvi, Bible rv,
                                   Abbreviations abrev)
        {
            session = new WordSession();
            session.Show();
            session.Open(indiceDeTemasPath);

            NVI = nvi;
            RV = rv;

            Abrev = abrev;
        }

        #region Entries

        public static bool IsEntryParagraph(string text)
        {
            if (text.Contains(GuionLargoStr))
            {
                var parts = text.Split(new char[] { GuionLargoChar }).ToList();
                var posibleNumero = parts[0];
                int numero;
                if (int.TryParse(posibleNumero, out numero))
                {
                    return true;
                }
            }
            return false;
        }

        public void ParseEntries()
        {
            session.Split(IsEntryParagraph);
        }

        public string SearchSubstringToReplace(string text)
        {
            string[] parts = text.Split(new char[] { ',' });
            return parts[0];
        }

        public void ReplaceEntries()
        {
            session.ReplaceParagraphsText(SearchSubstringToReplace, SearchReplacement);
        }

        #endregion

        #region Verses

        public static bool IsVerseParagraph(string text)
        {
            string[] parts = text.Split(new char[] { ' ' });
            if (parts.Length > 0)
            {
                string book = parts[0];
                int num;
                if (int.TryParse(book, out num))
                    book += (" " + parts[1]);
                if (Abrev.IsAbrev(book.Replace("*", "")))
                {
                    return true;
                }
            }

            return false;

            //if (text.Contains(GuionLargoStr))
            //{
            //    var parts = text.Split(new char[] { GuionLargoChar }).ToList();
            //    var posibleNumero = parts[0];
            //    int numero;
            //    if (int.TryParse(posibleNumero, out numero))
            //    {
            //        return true;
            //    }
            //}
            //return false;
        }

        public int CountVerses()
        {
            session.Split(IsVerseParagraph);
            return session.sectionsParagraphs.Count;
        }

        public void ParseVerses()
        {
            session.Split(IsVerseParagraph);
        }

        public static Key GetKey(string paragraph)
        {
            string[] paragraphParts = paragraph.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            int partId = 0;
            if (paragraphParts.Length > 0)
            {
                string book = paragraphParts[partId++];
                int num;
                if (int.TryParse(book, out num))
                    book += (" " + paragraphParts[partId++]);
                if (!Abrev.IsAbrev(book.Replace("*", "")))
                    throw new Exception("Must be a book!");
                string[] referenceParts = null;
                int chapter = -1;
                int verse = -1;
                if (paragraphParts[partId].EndsWith(":"))
                {
                    referenceParts = paragraphParts[partId++].Split(new char[] { ':' });
                    chapter = int.Parse(referenceParts[0]);
                    string sverse = paragraphParts[partId++].Trim();
                    verse = int.Parse(sverse);
                }
                else
                {
                    referenceParts = paragraphParts[partId++].Split(new char[] { ':' });
                    chapter = int.Parse(referenceParts[0]);
                    verse = int.Parse(referenceParts[1]);
                }

                return new Key(book, chapter, verse);
            }
            throw new Exception("We have a problem!");
        }

        public static Key ConvertToFullKey(Key key)
        {
            return new Key(Abrev.GetBookName(key.Book.Replace("*", "")), key.Chapter, key.Verse);
        }

        public List<Fragment> ParseExactVerses()
        {
            return session.Extract(IsVerseParagraph, GetCharsCount, GetKey, ConvertToFullKey, GetNVI, GetRV);
        }

        public List<Fragment> ParseVersesWithRegex()
        {
            return session.ExtractWithRegex(IsVerseParagraph, GetCharsCount, GetKey, ConvertToFullKey, GetNVI, GetRV);
        }

        public void ReplaceVerses()
        {
            session.ReplaceParagraphsText(SearchVerseToReplace, SearchVerseReplacement);
        }

        public void ReplaceVerses(List<Fragment> fragments)
        {
            session.ReplaceText2(GetRV, fragments);
        }

        public void HighlightVerses()
        {
            session.HighlightText();
        }

        public string SearchVerseToReplace(string text)
        {
            string[] parts = text.Split(new char[] { ',' });
            return parts[0];
        }

        //Sal 36:8 Se sacian de la abundancia de tu casa; les das a beber de tu río de deleites.

        public string SearchVerseReplacement(string text)
        {
            string[] parts = text.Split(new char[] { ' ' });
            string shortBook = parts[0];
            string bookName = Abrev.GetBookName(shortBook.Replace("*", ""));
            string schandv = parts[1];
            string[] pchandv = schandv.Split(new char[] { ':' });
            int chapter = int.Parse(pchandv[0]);
            int verse = int.Parse(pchandv[1]);
            string plainPassage = text.Replace(string.Format("{0} {1}", shortBook, schandv), "").Trim();

            //TODO: comprobar que el texto a reemplazar sea el correcto
            string passageNVI = NVI.GetPlainPassage(new Key(bookName, chapter, verse));
            string passageRV = RV.GetPlainPassage(new Key(bookName, chapter, verse));

            return string.Format("{0} {1}:{2} {3}", shortBook, chapter, verse, passageRV);
        }

        public string GetNVI(Key key)
        {
            return NVI.GetPlainPassage(key);
        }

        public string GetRV(Key key)
        {
            return RV.GetPlainPassage(key);
        }

        #endregion

        public void Close()
        {
            session.Close();
            session.Quit();
        }

        private static Abbreviations Abrev { get; set; }

        public int GetCharsCount(Key key)
        {
            Logger.WriteLine("Chars count: {0}", key);
            string text = NVI.GetPlainPassage(key);
            Logger.WriteLine("{0} -> {1}", text.Length, text);
            return text.Length;
        }

        ModificacionesEntradas modifEntradas { get; set; }
        string ModifEntradasXLSPath { get { return Config.RootPath + @"\Modificaciones entradas (2012).xls"; } }
        string ModifEntradasBinPath { get { return Config.RootPath + @"\BIN\ModifEntradas.bin"; } }

        private void LoadEntryReplacements()
        {
            modifEntradas = new ModificacionesEntradas();

            ExcelSession excel = new ExcelSession();
            var ws = excel.Open(ModifEntradasXLSPath);
            Logger.WriteLine("TotalME: {0}", ws.Rows.Count);
            int errors = 0;
            for (int i = 1; i < ws.Rows.Count && errors < 10; i++)
            {
                if (!modifEntradas.Add(((string)((Excel.Range)ws.Cells[i, 1]).Text),
                                       ((string)((Excel.Range)ws.Cells[i, 2]).Text),
                                       ((string)((Excel.Range)ws.Cells[i, 3]).Text)))
                {
                    Logger.WriteLine("Item ignorado: {0}, {1}, {2}",
                                     ((string)((Excel.Range)ws.Cells[i, 1]).Text),
                                     ((string)((Excel.Range)ws.Cells[i, 2]).Text),
                                     ((string)((Excel.Range)ws.Cells[i, 3]).Text));
                    errors++;
                }
                Logger.WriteLine("ActualME: {0}", i);
            }
            excel.Close();
            excel.Quit();

            modifEntradas.Serialize<ModificacionesEntradas>(ModifEntradasBinPath);
        }

        public string SearchReplacement(string text)
        {
            if (modifEntradas == null)
                LoadEntryReplacements();
            string[] parts = text.Split(new char[] { IndiceDeTemasParser.GuionLargoChar });
            int numero = int.Parse(parts[0]);
            string texto = parts[1];

            ModificacionEntrada modificacion = modifEntradas[texto];
            if (modificacion != null)
            {
                return string.Format("{0}{1}{2}", numero, IndiceDeTemasParser.GuionLargoChar, modificacion.TemaRV);
            }
            else
                return null;
        }

        public void ReplaceEntriesWithRegex(Func<int, int> rvIdFromNVIId/*, Func<int, string> rvEntryFromNVIId*/)
        {
            session.ReplaceEntriesWithRegex(SearchEntryReplacement, rvIdFromNVIId/*, rvEntryFromNVIId*/);
        }

        /// <summary>
        /// Segunda implementación de SearchReplacement, esta devuelve los contenidos descompuestos para que la capa superior
        /// decida como aplicarlos al texto bíblico
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>

        private Tuple<int, string, string> SearchEntryReplacement(string text)
        {
            if (modifEntradas == null)
                LoadEntryReplacements();

            ModificacionEntrada modificacion = modifEntradas.FindMatchWithBegginingOfText(text);

            if (modificacion != null)
                return new Tuple<int, string, string>(modificacion.NumeroRV.Value, modificacion.TemaNVI, modificacion.TemaRV);

            return null;
        }

        public void ReplaceVease(Func<int, int> rvIdFromNVIId)
        {
            session.ReplaceVease(rvIdFromNVIId);
        }

        public void ReplaceWords()
        {
            if (modifEntradas == null)
                LoadEntryReplacements();
            Dictionary<string, string> words = new Dictionary<string, string>();
            modifEntradas.Entradas.ForEach(x => words[x.TemaNVI] = x.TemaRV);
            session.ReplaceWords(words);
        }
    }
}
